﻿using Cinchoo.Core;
using Cinchoo.Core.Compiler;
using Cinchoo.Core.Diagnostics;
using Cinchoo.Core.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;

namespace ChoBulkFileProcessor
{
    [Serializable]
    public class ChoUndoFileProcessState
    {
        public string SourceFilePath;
        public string DestFilePath;
        public bool IsFolder;
        public bool DoDelete;
    }

    public class ChoUndoFileProcessManager
    {
        public readonly static Lazy<ChoUndoFileProcessManager> Default = new Lazy<ChoUndoFileProcessManager>(() => new ChoUndoFileProcessManager());

        private readonly ChoAppSettings _appSettings;
        private readonly List<ChoUndoFileProcessState> _fileList = new List<ChoUndoFileProcessState>();
        private readonly string _undoScriptsFolder;
        private bool _canUndo;

        public ChoUndoFileProcessManager()
        {
            _appSettings = new ChoAppSettings();

            _undoScriptsFolder = _appSettings.UndoScriptsFolder;
            if (_undoScriptsFolder.IsNullOrWhiteSpace())
                _undoScriptsFolder = "UndoScripts";

            _undoScriptsFolder = ChoPath.GetFullPath(_undoScriptsFolder);
            Initialize();
        }

        public void Initialize()
        {
            _canUndo = false;
            _fileList.Clear();
        }

        public void AddUndoEntry(string sourceFilePath, string destFilePath, bool isFolder = false, bool doDelete = false)
        {
            ChoGuard.ArgumentNotNullOrEmpty(sourceFilePath, "SourceFilePath");

            _canUndo = true;
            _fileList.Add(new ChoUndoFileProcessState() { SourceFilePath = sourceFilePath, DestFilePath = destFilePath, IsFolder = isFolder, DoDelete = doDelete });
        }

        public void AddUndoEntryAtBegin(string sourceFilePath, string destFilePath, bool isFolder = false, bool doDelete = false)
        {
            ChoGuard.ArgumentNotNullOrEmpty(sourceFilePath, "SourceFilePath");

            _canUndo = true;
            _fileList.Insert(0, new ChoUndoFileProcessState() { SourceFilePath = sourceFilePath, DestFilePath = destFilePath, IsFolder = isFolder, DoDelete = doDelete });
        }

        public string Save()
        {
            return Save("Undo_{0}.{1}".FormatString(DateTime.Now.ToString("yyyyMMdd_HH_mm_ss"), ChoReservedFileExt.Xml));
        }

        public string Save(string filePath)
        {
            ChoGuard.ArgumentNotNullOrEmpty(filePath, "UndoFilePath");
            if (_fileList.Count == 0) return filePath;

            if (!Path.IsPathRooted(filePath))
                filePath = Path.Combine(_undoScriptsFolder, filePath);

            ChoDirectory.CreateDirectoryFromFilePath(filePath);
            ChoObject.XmlSerialize(filePath, _fileList);
            _fileList.Clear();

            return filePath;
        }

        public void Undo(string filePath)
        {
            ChoGuard.ArgumentNotNullOrEmpty(filePath, "UndoFilePath");

            StringBuilder msg = new StringBuilder();
            foreach (ChoUndoFileProcessState fileEntry in ChoObject.XmlDeserializeFromFile<List<ChoUndoFileProcessState>>(filePath))
            {
                if (fileEntry.DestFilePath.IsNullOrWhiteSpace()) continue;

                if (fileEntry.IsFolder)
                {
                    if (!fileEntry.DoDelete)
                        msg.AppendLine(@"System.IO.Directory.Move(@""{0}"", @""{1}"");".FormatString(fileEntry.DestFilePath, fileEntry.SourceFilePath));
                    else
                        msg.AppendLine(@"System.IO.Directory.Delete(@""{0}"", true);".FormatString(fileEntry.DestFilePath));
                }
                else
                {
                    if (!fileEntry.DoDelete)
                        msg.AppendLine(@"Cinchoo.Core.IO.ChoFile.Move(@""{0}"", @""{1}"");".FormatString(fileEntry.DestFilePath, fileEntry.SourceFilePath));
                    else
                        msg.AppendLine(@"System.IO.File.Delete(@""{0}"");".FormatString(fileEntry.DestFilePath));
                }
            }

            ChoTrace.WriteLineIf(ChoTraceSwitch.Switch.TraceVerbose, msg.ToString());
            ChoCodeDomProvider cs = new ChoCodeDomProvider(new string[] { msg.ToString() }, null);
            cs.ExecuteAction();

            //string batchFilePath = ChoPath.ChangeExtension(filePath, ChoReservedFileExt.BAT);

            //StringBuilder msg = new StringBuilder();
            //foreach (ChoUndoRenameFileState fileEntry in ChoObject.Deserialize<List<ChoUndoRenameFileState>>(filePath))
            //    msg.AppendLine(@"@MOVE /Y ""{0}"" ""{1}""".FormatString(fileEntry.DestFilePath, fileEntry.SourceFilePath));

            //File.WriteAllText(batchFilePath, msg.ToString());

            //using (ChoProcess p = new ChoProcess(batchFilePath))
            //{
            //    return p.Execute().StdOut;
            //}
        }

        //public string Undo()
        //{
        //    if (_fileList.Count == 0) return String.Empty;

        //    string tmpFilePath = ChoPath.GetTempFileName();
        //    tmpFilePath = ChoPath.ChangeExtension(tmpFilePath, ChoReservedFileExt.BAT);
        //    Save(tmpFilePath);

        //    using (ChoProcess p = new ChoProcess(tmpFilePath))
        //    {
        //        Initialize();
        //        return p.Execute().StdOut;
        //    }
        //}

        public bool CanUndo
        {
            get { return _canUndo; }
        }
    }
}
